"""
# -*- coding: utf-8 -*-
# @Time    : 2023/5/29 17:07
# @Author  : 王摇摆
# @FileName: Pocket_Manual.py
# @Software: PyCharm
# @Blog    ：https://blog.csdn.net/weixin_44943389?type=blog
"""
import numpy as np


def errorIndexes(W, X, y):
    """
    获取错误点的下标集合
    args:
        W - 权重系数
        X - 训练数据集
        y - 目标标签值
    return:
        errorIndexes - 错误点的下标集合
    """
    errorIndexes = []
    # 遍历训练数据集
    for index in range(len(X)):
        x = X[index]
        # 判定是否与目标值不符
        if x.dot(W) * y[index] <= 0:
            errorIndexes.append(index)
    return errorIndexes


def pocket(X, y, iteration, maxIterNoChange=10):
    """
    口袋算法实现
    args:
        X - 训练数据集
        y - 目标标签值
        iteration - 最大迭代次数
    return:
        W - 权重系数
    """
    np.random.seed(42)
    # 初始化权重系数
    W = np.zeros(X.shape[1])
    # 获取错误点的下标集合
    errors = errorIndexes(W, X, y)
    iterNoChange = 0
    # 循环
    for i in range(iteration):
        iterNoChange = iterNoChange + 1
        # 随机获取错误点下标
        errorIndex = np.random.randint(0, len(errors))
        # 计算临时权重系数
        tmpW = W + y[errors[errorIndex]] * X[errorIndex]
        # 获取临时权重系数下错误点的下标集合
        tmpErrors = errorIndexes(tmpW, X, y)
        # 如果错误点数量更少，就更新权重系数
        if len(errors) >= len(tmpErrors):
            iterNoChange = 0
            # 修正权重系数
            W = tmpW
            errors = tmpErrors
        if iterNoChange >= maxIterNoChange:
            break
    return W
